package bma.common.langutil.ai;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import bma.common.langutil.ai.objectpool.AIKeyedPoolableObjectFactory;
import bma.common.langutil.ai.objectpool.GenericAIKeyedObjectPool;
import bma.common.langutil.ai.stack.AIStack;
import bma.common.langutil.ai.stack.AIStackAbstract;
import bma.common.langutil.ai.stack.AIStackNone;
import bma.common.langutil.ai.stack.AIStackSimple;
import bma.common.langutil.ai.vm.AIVM;
import bma.common.langutil.core.ObjectUtil;

public class AIObjectPoolTC {

	private class Factory1 implements
			AIKeyedPoolableObjectFactory<String, String> {
		@Override
		public boolean validateObject(String key, String obj) {
			return true;
		}

		@Override
		public void passivateObject(String key, String obj) {
		}

		@Override
		public boolean makeObject(AIStack<String> stack, String key) {
			return stack.success(Long.toString(System.currentTimeMillis()));
		}

		@Override
		public void destroyObject(String key, String obj) {
		}

		@Override
		public void activateObject(String key, String obj) {
		}
	}

	private class Factory2 extends Factory1 {

		@Override
		public boolean makeObject(final AIStack<String> stack, String key) {
			main.execute(null, new Runnable() {

				@Override
				public void run() {
					log.info("create !!!!");
					stack.success(Long.toString(System.currentTimeMillis()));
				}
			});
			return false;
		}

	}

	final org.slf4j.Logger log = org.slf4j.LoggerFactory
			.getLogger(AIObjectPoolTC.class);

	AIVM main;

	@Before
	public void setupMain() {
		main = new AIVM();
		main.installMain();
	}

	@After
	public void closeMain() {
		main.close();
	}

	@Test
	public void borrowAndReturn() throws Exception {
		GenericAIKeyedObjectPool<String, String> pool = new GenericAIKeyedObjectPool<String, String>();
		pool.setFactory(new Factory1());
		pool.setTimer(main.sureTimer());
		pool.setWaitTimeout(1000);
		pool.setMaxIdle(2);
		pool.setMaxActive(2);

		// borrowAndReturn
		for (int i = 0; i < 2; i++) {
			AIStackSimple<String> s = new AIStackSimple<String>(null);
			pool.borrowObject(s, "test");
			String str = s.get();
			log.info(str);
			pool.returnObject("test", str);
		}

		// max active
		pool.borrowObject(new AIStackNone<String>(), "test");
		pool.borrowObject(new AIStackNone<String>(), "test");
		pool.borrowObject(new AIStackAbstract<String>() {

			@Override
			public boolean success(String result) {
				log.info("get it - {}", result);
				return true;
			}

			@Override
			public boolean failure(Throwable t) {
				log.error("" + t);
				return true;
			}

			@Override
			public AIStack<?> getParent() {
				return null;
			}

		}, "test");
		log.info("here {},", pool);

		// max idle
		for (int i = 0; i < 5; i++) {
			pool.returnObject("test", Integer.toString(i));
		}

		ObjectUtil.waitFor(this, 1000);

		pool.close();
	}

	@Test
	public void idleTimeout() throws Exception {
		GenericAIKeyedObjectPool<String, String> pool = new GenericAIKeyedObjectPool<String, String>();
		pool.setFactory(new Factory1());
		pool.setTimer(main.sureTimer());
		pool.setMaxIdle(10);
		pool.setMinIdle(2);
		// pool.setLifo(true);
		pool.setIdleMaxTime(1000);
		pool.setEvictIdleTime(500);

		// borrowAndReturn
		for (int i = 0; i < 3; i++) {
			pool.returnObject("test", "" + i);
			// ObjectUtil.waitFor(this, 100);
		}

		System.out.println(pool.toString());
		ObjectUtil.waitFor(this, 3000);

		pool.borrowObject(new AIStackNone<String>(), "test");

		pool.close();
	}

	@Test
	public void aiCreate() throws Exception {
		GenericAIKeyedObjectPool<String, String> pool = new GenericAIKeyedObjectPool<String, String>();
		pool.setFactory(new Factory2());
		pool.setTimer(main.sureTimer());
		pool.setMaxIdle(10);
		pool.setMinIdle(2);

		for (int i = 0; i < 2; i++) {
			AIStackSimple<String> s = new AIStackSimple<String>(null);
			pool.borrowObject(s, "test");
			String str = s.get();
			log.info(str);
			pool.returnObject("test", str);
		}

		System.out.println(pool.toString());
		ObjectUtil.waitFor(this, 3000);

		pool.close();
	}
}
